package demo.netty.nio;


import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

/**
 * 处理TCP 拆包和粘包现象
 */
public class TcpUnpacking {


    public static class Client {
        public static void main(String[] args) throws IOException {
            new Client().start();
        }

        public void start() throws IOException {
            SocketChannel socketChannel = SocketChannel.open();
            socketChannel.connect(new InetSocketAddress("127.0.0.1", 8001));
            senderMsg(socketChannel);
        }

        private void senderMsg(SocketChannel socketChannel) throws IOException {
            byte[] bytes = {0x00, 0x00, 0x10, 0x7E};
            ByteBuffer wrap = ByteBuffer.wrap(bytes);
            socketChannel.write(wrap);
        }
    }


    public static class Server {

        public static void main(String[] args) throws IOException {
            new Server().start();
        }

        public void start() throws IOException {
            ServerSocketChannel socketChannel = ServerSocketChannel.open();
            socketChannel.bind(new InetSocketAddress(8001));
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            while (true) {
                System.out.println("=====================开启服务监听=====================");
                SocketChannel channel = socketChannel.accept();
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                channel.read(buffer);
                doProcess(channel, buffer, outputStream);
                System.out.println(outputStream);
                System.out.println("=====================数据处理完毕=====================");
            }
        }

        private boolean doProcess(SocketChannel socketChannel, ByteBuffer buffer, ByteArrayOutputStream outputStream) throws IOException {
            //记录上起点索引
            buffer.mark();
            //读取出所有没有读的数据
            byte[] bytes = new byte[buffer.remaining()];
            buffer.get(bytes);
            //将缓存数据进行重置到mark标记处
            buffer.reset();
            //循环遍历数据
            while (buffer.remaining() > 0) {
                buffer.mark();
                int mark = buffer.position();
                byte tag = buffer.get();
                //搜索当前包开头是否是 7E进行开头，防止 第一个字节和第二个字节都是7E，默认取第二个作为包的开头
                if (0x7E == tag && buffer.remaining() > 0) {
                    tag = buffer.get();
                    //判断是否是 7E结尾
                    while (tag != 0x7E) {
                        //如果不是7E结尾，并且数据已经读取完毕，那么证明出现了拆包，就不需要处理
                        if (buffer.remaining() <= 0) {
                            //重置到mark标记处
                            buffer.reset();
                            return false;
                        }
                        //继续读取数据，直到读取到 7E结尾数据
                        tag = buffer.get();
                    }
                }
                //执行到这一步证明 读取的数据 7E 开头到7E结尾的数据了
                int position = buffer.position();
                //读取包的长度
                int packLength = position - mark;
                System.out.println("包的长度：" + packLength);
                byte[] data = new byte[packLength];
                buffer.get(data, position, packLength);
                outputStream.write(data);
            }
            return false;
        }

    }



}
